using KinonekoSoftware.Extensions.Collections;

namespace KinonekoSoftware.CodariaDB.Documents.Templates
{
    public static class DataPartTypeHelper
    {

        private static readonly Dictionary<string, List<DataPartTypeSelector>> _MutexDictionary;
        private static readonly Dictionary<DataPartType, string>               _FindMutexByType;
        private static readonly ObservableCollection<DataPartTypes>            _DataPartTypes;

        static DataPartTypeHelper()
        {
            _MutexDictionary = new Dictionary<string, List<DataPartTypeSelector>>();
            _DataPartTypes   = new ObservableCollection<DataPartTypes>();
            _FindMutexByType = new Dictionary<DataPartType, string>();
            Mutex            = new ReadOnlyDictionary<string, List<DataPartTypeSelector>>(_MutexDictionary);
            Types            = new ReadOnlyObservableCollection<DataPartTypes>(_DataPartTypes);
            GetMutex         = new ReadOnlyDictionary<DataPartType, string>(_FindMutexByType);
            Initialize();
        }

        private static void Initialize()
        {
            var type = typeof(DataPartType);


            var values = Enum.GetNames(type)
                             .Select(x => type.GetField(x))
                             .Where(x => x is not null)
                             .Select(x =>
                              {
                                  var value = Enum.Parse<DataPartType>(x.Name);
                                  var attr  = (Attribute.GetCustomAttribute(x, typeof(MetadataAttribute)) as MetadataAttribute);

                                  if (attr is null)
                                  {
                                      return null;
                                  }
                                  
                                  return new DataPartTypeSelector
                                  {
                                      Name     = LanguageManager.GetEnum(value),
                                      Mutex    = attr.Mutex,
                                      Category = attr.Value,
                                      Icon     = attr.Icon,
                                      Type     = value,
                                  };
                              })
                             .Where(x => x is not null);
            
            var dict = new Dictionary<string, DataPartTypes>();

            foreach (var selector in values)
            {
                if (!string.IsNullOrEmpty(selector.Mutex))
                {
                    //
                    //
                    _FindMutexByType.TryAdd(selector.Type, selector.Mutex);

                    //
                    //
                    if (_MutexDictionary.TryGetValue(selector.Mutex, out var container))
                    {
                        container.Add(selector);
                    }
                    else
                    {
                        container = new List<DataPartTypeSelector>
                        {
                            selector,
                        };
                        _MutexDictionary.Add(selector.Mutex, container);
                    }
                }

                if (dict.TryGetValue(selector.Category, out var dpts))
                {
                    dpts.Items.Add(selector);
                }
                else
                {
                    dpts = new DataPartTypes
                    {
                        Name  = LanguageManager.GetText(selector.Category),
                        Items = new List<DataPartTypeSelector> { selector },
                    };
                    dict.Add(selector.Category, dpts);
                }
            }

            _DataPartTypes.AddMany(dict.Select(x => x.Value), true);
        }


        public static ReadOnlyDictionary<string, List<DataPartTypeSelector>> Mutex    { get; }
        public static ReadOnlyObservableCollection<DataPartTypes>            Types    { get; }
        public static ReadOnlyDictionary<DataPartType, string>               GetMutex { get; }
    }
}